1.7-工具对象
Create by fall on 26 May 2021 Recently revised in 06 Apr 2023
Math
Math 用于 Number 类型数据处理。它不支持 BigInt。
方法 | 作用 |
---|---|
Math.abs() | 返回取绝对值 |
Math.max() | 传入逗号分割的多个数,返回最大的参数 |
Math.min() | 传入逗号分割的多个数,返回最小的参数 |
Math.round() | 四舍五入到最接近的整数 |
Math.ceil() | 返回向上取整的值 |
Math.floor() | 返回向下取整的值 |
Math.random() | 返回 0~1 随机数,无需传入值 |
Math.E | 常数 e≈2.71828 |
Math.trunc() | 返回该数值的整数部分 |
Math.sign() | 返回数值的类型,1 表示正数,-1 表示负数,0 |
Math.cbrt() | 返回数值立方根 |
Math.clz32() | 返回数值的 32 位无符号整数形式,即32-该数值的二进制表示位数 |
Math.imul(a,b) | 返回两个数相乘 |
Math.fround() | 返回数值的 32 位单精度浮点数形式 |
Math.pow(x,y) | 求 x 的 y 次方 |
Math.abs(-130) // 130
Math.max(22,66,99) // 99
Math.min(-22,66) // -22
Math.round(Math.PI) // 3
Math.round(Math.E) // 3
Math.ceil(1.1) // 2 向上取整
Math.floor(1.9) // 1 向下取整
Math.hypot()
返回所有数值平方和的平方根Math.hypot(4,4,4,4) == 8
Math.expm1()
: 返回e^n - 1
Math.log1p()
:返回 1 + n 的自然对数(Math.log(1 + n)
)Math.log10()
:返回以 10 为底的 n 的对数Math.log2()
:返回以 2 为底的n的对数Math.sinh()
:返回 n 的双曲正弦Math.cosh()
:返回 n 的双曲余弦Math.tanh()
:返回 n 的双曲正切Math.asinh()
:返回 n 的反双曲正弦Math.acosh()
:返回 n 的反双曲余弦Math.atanh()
:返回 n 的反双曲正切
RegExp
正则表达式,详情可见【正则】
对象特性
// 正则表达式的声明
const reg1 = new RegExp('hello','ig')
const reg2 = new RegExp(/xYz\d+/gi, i) // 如果传入了第二个参数,以第二个为准
const reg3 = RegExp('hello','ig')
const reg4 = /hello/gi
// i 表示不区分大小写,g 表示可以同时选取多个,m 表示可以换行匹配,每一行的内容独立
reg.flags // 可以返回当前正则的所有修饰符
修饰符
u
处理大于\uFFFF
的Unicode
字符i
表示不区分大小写g
表示可以同时选取多个m
表示可以换行匹配,每一行的内容独立y
同样是全局匹配,只不过匹配必须连在一起s
dotAll,只要有点,可以用.
代替所有字符
u
修饰符:含义为 Unicode
模式,用来正确处理大于 \uFFFF
的 Unicode
字符。也就是说,如果待匹配的字符串中可能包含有大于 \uFFFF
的字符,就必须加上 u
修饰符,才能正确处理。
// 加上 u 修饰符才能让 . 字符正确识别大于 \uFFFF 的字符
/^.$/.test('🤣') // false
/^.$/u.test('🤣') // true
// 大括号 Unicode 字符表示法必须加上 u 修饰符
/\u{61}/.test('a') // false
/\u{61}/u.test('a') // true
// 有 u 修饰符,量词才能正确匹配大于 \uFFFF 的字符
/🤣{2}/.test('🤣🤣') // false
/🤣{2}/u.test('🤣🤣') // true
RegExp.prototype.unicode
属性表示正则是否设置了 u
修饰符:
/🤣/.unicode // false
/🤣/u.unicode // true
y
修饰符,与 g
修饰符类似也是全局匹配;不同的是 g
是剩余字符中匹配即可,而 y
则是必须在剩余的第一个字符开始匹配才行,所以 y
修饰符也叫黏连修饰符:
let s = 'aaa_aa_a'
let r1 = /a+/g
let r2 = /a+/y
r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]
r1.exec(s) // ["aa"]
r2.exec(s) // null
RegExp.prototype.sticky
属性表示是否设置了 y
修饰符:
/abc/y.sticky // true
s
修饰符,开启 dotAll 模式,ES2018引入,通过 .
表示任意字符
/fall.again/.test('fall\nagain') // false
/fall.again/s.test('fall\nagain') // true
具名匹配,可以将捕获的字符串进行命名,通过命名进行快速查找
没有使用具名匹配
let day = /(\d{4})-(\d{2})-(\d{2})/
let result = day.exec('2021-08-12')
// result[0] === '2021-08-12'
// result[1] === '2021'
// result[2] === '08'
// result[3] === '12'
使用具名匹配
let day = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
let result = day.exec('2021-08-12')
// result.groups { year: "2021", month: "08", day: "12" }'
配合结构赋值
let {groups: {year, month, day}} = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/.exec('2021-08-12')
console.log(year, month, day) // 2021 08 12
后行断言 (?<=y)x
,x
只有在 y
后面才能匹配:
/(?<=\$)\d+/.exec('I have $100.') // ['100']
// 否定断言: (?<!y)x,x 只有不在 y 后面才能匹配:
/(?<!\$)\d+/.exec('I have $100.') // ['00']
实例方法
reg.test()
测试是否符合,返回true
或者false
reg.dotAll()
检测该正则是否处在 dotAll 模式reg.exec()
返回符合的字符串组成的数组。
JSON
JSON 对象只有两个实例方法,即
JSON.stringify()
JSON.parse()
实例方法
JSON.stringify
基本用法:JSON.stringify(value[, replacer [, space]])
第三个参数作用是指定 space 个空格的缩进,想让代码更好看一点,就写上空格缩进(对象是引用类型,对象的调试可能会用到该参数)。
0xD800
到 0xDFFF
之间的码点不能单独使用,所以 JSON.stringify()
对单个码点进行操作,如果符合 UTF-8
标准,会返回对应的字符,如果不满足会返回对应的码点。
let replacerFun = function (key, value) {
console.log(key, value)
if (key === 'name') { // 如果key 等于 name<直接返回 undefined
return undefined // 返回 undefined 时,该键值对直接忽略,
}
return value
}
let myIntro = {
name: 'fall',
age: 25,
like: 'FE'
}
JSON.stringify(myIntro, replacerFun) // {"age":25,"like":"FE"}
实现对象的深拷贝
let info = {
name:'fall'
age: 25,
like: 'FE'
}
function deepClone() {
return JSON.parse(JSON.stringify(myIntro))
}
let copyMe = deepClone(myIntro)
copyMe.like = 'Front End'
console.log(myIntro, copyMe)
// { age: 25, like: 'FE' } { age: 25, like: 'Front End' }
特别注意:
JSON.stringify(Infinity)
之后,会存储的是 null,读取后,不是 Infinity以下情况使用
JSON.stringify()
可能会出错,请确保使用前没有一下情况出现。
- 转换属性值中有 toJSON 方法时。方法不会被JSON.stringify 识别,但如果是 toJSON,该方法会直接被执行,并且不会返回生成的字符串。详见例1。
- 被转换值中有 undefined、任意的函数以及 symbol 值。详见例2、例3
- 值为 NaN 和 Infinity。详见例2、例3
- 以 symbol 为属性键的属性
- 包含循环引用的对象,objA引用 objB,并且 objB 引用 objA
- 具有不可枚举的属性值时
var num = Infinity
JSON.stringify(num) // "null"
// 例1:
let author = {
name:'fall',
age:23,
toJSON:function(){
return "成功"
}
}
JSON.stringify(author) // "\"成功\""
// 例2:
let author = {
wife:undefined,
money:Infinity,
string:NaN,
girlfriend:Symbol("she")
}
JSON.stringify(author) // "{\"money\":null,\"like\":null}"
// 例3
let nothing = [undefined,Infinity,NaN,Symbol("she")]
JSON.stringify(nothing)
// 例4
let author = Object.create(null, {
name: { value: "fall", enumerable: true },
age: { value: "23", enumerable: false },
})
JSON.stringify(author)
// {"name":"fall"}
Proxy
代理,用来定义基本操作的自定义行为,对被代理对象 target
操作之前会先进行拦截。
- 实质上是目标对象
target
的包装 - 可以通过代理对象进行操作,也可以直接对
target
进行操作,两者相互独立存在,进行操作 - 只有通过 proxy操作时,才会被预设的方法拦截。直接操作对象,不会受到任何拦截影响。
// 创建代理对象,代理对象内有两个对象,一个是 target,表示被监听对象,另一个是 handler,表示做如何处理
// let proxy = new Proxy(target,handler)
// 代理对象的使用
let instance = new Proxy({user:'fall'},{
get(target,propKey,receiver){
return `你好啊,${target.name}`
}
})
// 在对被代理对象操作时,能进行拦截,并且获取的是代理处理后的返回值
instance.name // '你好啊,fall'
如果 handler
没有设置任何拦截,那么对实例的操作就会转发到目标对象身上(对代理赋值,直接作用于 target)
let target = {}
let proxy = new Proxy(target, {})
proxy.name = '布兰'
target.name // '布兰'
handler
get
用于拦截属性的读取操作set
用于拦截对象的属性操作has
拦截propKey in proxy
的操作,表示属性是否存在。deleteProperty
拦截delete
操作ownKeys
拦截Object.keys()
for...in
等循环getOwnPropertyDescriptor
获取对象上属性的描述对象时的代理defineProperty
命名对向上的属性描述时的代理preventExtensions
设置防止扩展属性是的代理getPrototypeOf
获取isExtensible
可否扩展的setPrototypeOf
apply
construct
let target={
name:'fall'
}
let proxy = new Proxy(target, {
get(target,propKey,receiver){},
// 拦截对象属性的读取,target 指的是被代理的对象,propKey 指受到操作的对象,receiver 表示该 Proxy 代理对象
set(target,propKey,value,receiver){},
// 拦截对于对象中属性值的设置,target 指的是被代理的对象,propKey 指受到操作的对象,value表示属性对应的值,receiver 表示该 Proxy 代理对象
has(target,propKey){},
// 拦截 propKey in proxy 操作,返回一个布尔值
deleteProperty(target,propKey){},
// 拦截删除 propKey 的操作
ownKeys(target){},
// 拦截多个Object操作,返回一个数组,数组包括所有值,不同于Object.keys(),可以返回Symbol对象
})
静态方法
Proxy.revocable()
定义一个可撤销的 Proxy
let target = {}
let handler = {}
let {proxy, revoke} = Proxy.revocable(target, handler)
proxy.foo = 123
proxy.foo // 123
revoke() // 执行结构的第二个方法,就可以撤销该 proxy
proxy.foo // TypeError
示例
get 示例
let staff = {
name:'fall',
age:13
}
const proxyStaff = new Proxy(staff,{
get(target,propKey,receiver){
console.log(target) // target 指向的是 staff
console.log(propKey) // propKey 指向的是 key age
console.log(receiver) // 指向的是 proxyStaff(一般不用添加这个参数)
// return `谁让你获取这个${propKey}数据的?不给!`
return 'nothing' // 如果想要使用默认获取值的操作,使用该返回值
},
})
console.log(proxyStaff.age)
// 如果获取本身不存在的值,则返回 undefined
// 如果定义了 return 'nothing',那么
proxyStaff.career // 'nothing'
set 示例
let staff = {
name:'fall',
age:13
}
const proxyStaff = new Proxy(staff,{
set(target,propKey,value,receiver){
console.log(target) // target 指向的是 staff
console.log(propKey) // propKey 指向的是 key age
console.log(value) // 指向的是赋的值 此处为 23
console.log(receiver)// 指向代理对象,此处指向 proxyStaff
target[propKey] = value
// 该关键字不需要 return ,在这里无意义
}
})
proxyStaff.age = 23
has 示例
let staff = {
name:'fall',
age:13
}
const proxyStaff = new Proxy(staff,{
has(target,propKey){
console.log(target) // target 指向的是 staff
console.log(propKey) // propKey 指向的是 key age
return propKey in target
}
})
if('age' in proxyStaff){
console.log(proxyStaff.age)
}
deleteProperty 示例
let staff = {
name:'fall',
age:13
}
const proxyStaff = new Proxy(staff,{
deleteProperty(target,propKey){
return delete proxyStaff.age // 此处只能返回 true & false,表示删除是否成功
}
})
if('age' in proxyStaff){
delete proxyStaff.age
console.log(proxyStaff)
}
ownKeys 示例
let staff = {
name:'fall',
age:13
}
const proxyStaff = new Proxy(staff,{
ownKeys(target){
return Object.keys(target)
// 用于拦截 Object.getOwnPropertyNames()、Object.keys()、Object.getOwnPropertySymbols()、for...in 等循环类操作
}
})
console.log(Object.keys(proxyStaff))
getOwnPropertyDescriptor
方法
let staff = {
name:'fall',
age:13
}
const proxyStaff = new Proxy(staff,{
getOwnPropertyDescriptor(target,propKey){
return Object.getOwnPropertyDescriptor(target,propKey)
// 用于拦截 Object.getOwnPropertyDescriptor()
}
})
console.log(Object.getOwnPropertyDescriptor(proxyStaff,'name'))
defineProperty
方法
let staff = {
name:'fall',
age:13
}
const proxyStaff = new Proxy(staff,{
defineProperty(target,propKey,propKeyDesc){
return Object.defineProperty(target,propKey,propKeyDesc)
// 用于拦截 Object.defineProperty() propKeyDesc 是可定义的对象的属性
}
})
console.log(Object.defineProperty(proxyStaff,'hobby',{value:'beauty'}))
preventExtension
方法
let staff = {
name:'fall'
}
const proxyStaff = new Proxy(staff,{
preventExtensions(target){
return Object.preventExtensions(target)
// 用于拦截 Object.defineProperty() propKeyDesc 是可定义的对象的属性
}
})
Object.preventExtensions(proxyStaff)
proxyStaff.age = 23
console.log(proxyStaff.age) // undefined
getPrototypeOf
方法
let staff = {
name:'fall'
}
const proxyStaff = new Proxy(staff,{
getPrototypeOf(target){
return Object.getPrototypeOf(target)
}
})
console.log(Object.getPrototypeOf(proxyStaff))
isExtensible
方法
let staff = {
name:'fall'
}
const proxyStaff = new Proxy(staff,{
isExtensible(target){
return Object.isExtensible(target)// 返回一个布尔值,表示是否可以扩展
// return false // 直接返回 false 会报错
}
})
console.log(Object.isExtensible(proxyStaff))
setPrototypeOf
方法
// 调用 Object.setPrototypeOf() 时,会触发该函数
let staff = {
name:'fall',
age:13
}
const proxyStaff = new Proxy(staff,{
setPrototypeOf(target,proto){
// 设置原型方法会调用该函数
console.log(`向${target}的上,设置了${proto}原型`);
return Object.setPrototypeOf(target,proto)
}
})
console.log(Object.setPrototypeOf(proxyStaff,{}))
apply 方法
// 调用 Object.setPrototypeOf() 时,会触发该函数
function app(x,y){return x+y}
const proxyStaff = new Proxy(app,{
apply(target,object,args){
// object 是 this 参数的指向
// args 是参数列表
console.log('调用了该app方法')
return app.call(object,...args)
}
})
console.log(app(5,6))
construct 方法
// 调用 Object.setPrototypeOf() 时,会触发该函数
function App(x,y){return x+y}
const proxyStaff = new Proxy(App,{
construct(target,args){
console.log(args[0]);
return new App(...args)
}
})
console.log(new proxyStaff(42,12))
Reflect
Reflect 不是一个构造函数,不能通过 new
进行调用,更像是 Math,提供了很多静态方法提供调用。
Reflect 的作用是恢复到原来的默认值操作
- 它提供拦截
JavaScript
操作的方法。这些方法与proxy handlers
的方法相同。 - 设计的目的:
- 将
Object
属于语言内部的方法放到Reflect
上; - 修改某些
Object
方法的返回结果,让其变得更合理; - 让
Object
操作变成函数行为 Proxy handles
与Reflect
方法一一对应,前者用于定义自定义行为,而后者用于恢复默认行为;
- 将
静态方法
Reflect.apply(target, thisArgument, argumentsList)
对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和Function.prototype.apply()
功能类似;Reflect.construct(target, argumentsList[, newTarget])
对构造函数进行new
操作,相当于执行new target(...args)
;Reflect.defineProperty(target, propertyKey, attributes)
和Object.defineProperty()
类似。如果设置成功就会返回true
;Reflect.deleteProperty(target, propertyKey)
作为函数的delete
操作符,相当于执行delete target[name]
;Reflect.get(target, propertyKey[, receiver])
获取对象身上某个属性的值,类似于target[name]
;Reflect.getOwnPropertyDescriptor(target, propertyKey)
类似于Object.getOwnPropertyDescriptor()
。如果对象中存在该属性,则返回对应的属性描述符, 否则返回undefined
;Reflect.getPrototypeOf(target)
类似于Object.getPrototypeOf()
;Reflect.has(target, propertyKey)
判断一个对象是否存在某个属性,和in
运算符 的功能完全相同;Reflect.isExtensible(target)
类似于Object.isExtensible()
;Reflect.ownKeys(target)
返回一个包含所有自身属性(不包含继承属性)的数组。(类似于Object.keys()
, 但不会受enumerable
影响);Reflect.preventExtensions(target)
类似于Object.preventExtensions()
。返回一个Boolean
;Reflect.set(target, propertyKey, value[, receiver])
将值分配给属性的函数。返回一个Boolean
,如果更新成功,则返回true
;Reflect.setPrototypeOf(target, prototype)
设置对象原型的函数. 返回一个Boolean
, 如果更新成功,则返回true
;
Proxy 和 Reflect 是成对出现的,所以合起来就有一个示例
示例
// 这段代码中有地方完蛋了,应该是reflect是用错了,看看错在哪了
let staff = {
name:'fall',
age:13
}
const proxyStaff = new Proxy(staff,{
get(target,propKey,receiver){
console.log(target) // target 指向的是 staff
console.log(propKey) // propKey 指向的是 key age
console.log(receiver) // 指向的是 proxyStaff(一般就不用添加这个参数了)
// return `谁让你获取这个${propKey}数据的?不给!`
return Reflect.get(target, propKey) // 如果想要使用默认获取值的操作,使用该返回值
},
set(target,propKey,value){
console.log(target) // target 指向的是 staff
console.log(propKey) // propKey 指向的是 key age
console.log(value) // 指向的是赋的值 此处为 23
// target[propKey] = receiver //在此处意为:将staff.age 设置为 23
return Reflect.set(target,propKey,value) // 如果想要使用默认获取值的操作,使用该返回值
},
deleteProperty(target,propKey){
console.log(target) // target 指向的是 staff
console.log(propKey) // propKey 指向的是 key age
return Reflect.deleteProperty(target,propKey) // 如果想要使用默认获取值的操作,使用该返回值
}
})
delete proxyStaff.age
proxyStaff.age= 23
console.log(proxyStaff.age);
参考文章
作者 | 链接 |
---|---|
Gopal1 | https://www.jianshu.com/p/b714dc8e068e |